package com.zjb.demo.system.service;

import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.DateUtil;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.zjb.demo.common.constant.CacheConstants;
import com.zjb.demo.common.constant.UserConstants;
import com.zjb.demo.common.exception.ServiceException;
import com.zjb.demo.system.domain.SysConfig;
import com.zjb.demo.system.domain.dto.SysConfigPageQueryDto;
import com.zjb.demo.system.domain.query.SysConfigQuery;
import com.zjb.demo.system.mapper.SysConfigMapper;
import org.noear.redisx.plus.RedisBucket;
import org.noear.snack.core.utils.StringUtil;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

import java.util.List;

import static com.zjb.demo.system.domain.table.SysConfigTableDef.SYS_CONFIG;

/**
 * @author 庄佳彬
 * @since 2023/12/27 14:28
 */
@Component
public class SysConfigService extends ServiceImpl<SysConfigMapper, SysConfig> {
    @Inject
    private RedisBucket redisBucket;

    /**
     * 根据指定的查询条件分页查询系统配置信息
     *
     * @param query 查询条件
     * @return 分页结果对象
     */
    public Page<SysConfig> pageList(SysConfigQuery query) {
        var page = new Page<SysConfig>(query.getPageNum(), query.getPageSize());
        var start = DateUtil.parseDate(query.getBeginTime());
        var end = DateUtil.parseDate(query.getEndTime());
        return mapper.pageList(new SysConfigPageQueryDto(query.getConfigKey(), query.getConfigName(), query.getConfigType(), start, end, page));
    }

    /**
     * 根据给定的查询条件获取系统配置列表
     *
     * @param query 系统配置查询对象
     * @return 系统配置列表
     */
    public List<SysConfig> list(SysConfigQuery query) {
        var start = DateUtil.parseDate(query.getBeginTime());
        var end = DateUtil.parseDate(query.getEndTime());
        return mapper.list(new SysConfigPageQueryDto(query.getConfigKey(), query.getConfigName(), query.getConfigType(), start, end, null));
    }


    /**
     * 根据配置键获取配置值
     *
     * @param configKey 配置键
     * @return 配置值
     */
    public String getValueByKey(String configKey) {
        // 从Redis中获取配置值
        var value = redisBucket.getAndDeserialize(getCacheKey(configKey), String.class);
        // 如果Redis中存在配置值，则直接返回
        if (!StringUtil.isEmpty(value)) {
            return value;
        }
        // 如果Redis中不存在配置值，则从数据库中查询配置，并将查询结果存储到Redis中
        return mapper.selectByKey(configKey)
                .map(SysConfig::getConfigValue)
                .map(it -> {
                    redisBucket.storeAndSerialize(getCacheKey(configKey), it);
                    return it;
                })
                .orElse(StrUtil.EMPTY);
    }


    private String getCacheKey(String configKey) {
        return CacheConstants.SYS_CONFIG_KEY + configKey;

    }

    /**
     * 检查配置键是否唯一
     *
     * @param sysConfig 系统配置对象
     * @return 如果配置键唯一，返回true；否则，返回false
     */
    public boolean checkConfigKeyUnique(SysConfig sysConfig) {
        var query = QueryWrapper.create()
                .where(SYS_CONFIG.CONFIG_KEY.eq(sysConfig.getConfigKey()));
        return this.exists(query);
    }

    /**
     * 保存并缓存配置值
     *
     * @param sysConfig 需要保存和缓存的SysConfig对象
     * @return 保存成功与否的布尔值
     */
    public Boolean saveAndCache(SysConfig sysConfig) {
        var result = this.save(sysConfig);
        if (result) {
            redisBucket.storeAndSerialize(getCacheKey(sysConfig.getConfigKey()), sysConfig.getConfigValue());
        }
        return result;
    }


    /**
     * 更新并缓存配置值
     *
     * @param sysConfig 需要更新和缓存的SysConfig对象
     * @return 更新成功与否的布尔值
     */
    public Boolean updateAndCache(SysConfig sysConfig) {
        var result = this.updateById(sysConfig);
        if (result) {
            redisBucket.storeAndSerialize(getCacheKey(sysConfig.getConfigKey()), sysConfig.getConfigValue());
        }
        return result;
    }

    /**
     * 根据给定的configIds数组删除对应的SysConfig对象，并将其缓存删除
     *
     * @param configIds 需要删除的SysConfig对象的ID数组
     */
    public void removeByIdsAndCache(Long[] configIds) {
        for (Long configId : configIds) {
            var config = this.getById(configId);
            if (UserConstants.YES.equals(config.getConfigType())) {
                throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
            }
            this.removeById(configId);
            redisBucket.remove(getCacheKey(config.getConfigKey()));
        }
    }

    /**
     * 刷新缓存
     */
    public void refreshCache() {
        redisBucket.removeByPattern(CacheConstants.SYS_CONFIG_KEY + "*");
        this.list()
                .parallelStream()
                .forEach(config -> redisBucket.storeAndSerialize(getCacheKey(config.getConfigKey()), config.getConfigValue()));
    }

}
